package com.piece.core.framework.util.string;

import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import java.io.*;
import java.util.*;

/**
 * Document工具类
 */
@Slf4j
public class XmlUtil {

    /**
     * Document对象转String
     */
    public static String toString(Document document) {
        String result = "";
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            OutputFormat format = new OutputFormat("  ", true, "UTF-8");
            XMLWriter writer = new XMLWriter(out, format);
            writer.write(document);
            result = out.toString("UTF-8");
        } catch (Exception e) {
            log.error("Document文档转字符串异常：{}", e.getMessage());
        }
        return result;
    }

    /**
     * XML字符串转Document对象
     */
    public static Document toDocument(String xml) {
        Document doc = null;
        try {
            doc = DocumentHelper.parseText(xml);
        } catch (Exception e) {
            log.error("Xml字符转Document文档异常：{}", e.getMessage());
        }
        return doc;
    }

    /**
     * Document对象转XML文件
     *
     * @param document 文档对象
     * @param filepath 文件路径
     * @return
     */
    public static boolean toXmlFile(Document document, String filepath) {
        boolean flag = true;
        XMLWriter writer;
        try {
            OutputFormat format = OutputFormat.createPrettyPrint();
            format.setEncoding("UTF-8");
            writer = new XMLWriter(new FileOutputStream(new File(filepath)), format);
            writer.write(document);
            writer.close();
        } catch (Exception e) {
            flag = false;
            log.error("Document文档生成Xml文件异常：{}", e.getMessage());
        }
        return flag;
    }

    /**
     * String转XML文件
     *
     * @param xml      xml字符串
     * @param filepath 文件路径
     * @return
     */
    public static boolean toXmlFile(String xml, String filepath) {
        boolean flag = true;
        try {
            Document doc = DocumentHelper.parseText(xml);
            flag = toXmlFile(doc, filepath);
        } catch (Exception e) {
            flag = false;
            log.error("生成Xml文件异常：{}", e.getMessage());
        }
        return flag;
    }

    /**
     * 加载XML文件转成Document对象
     */
    public static Document load(String filepath) throws FileNotFoundException {
        return load(new FileInputStream(new File(filepath)));
    }

    /**
     * 加载XML文档转成Document对象
     */
    public static Document load(InputStream is) {
        Document document = null;
        try {
            SAXReader saxReader = new SAXReader();
            saxReader.setEncoding("UTF-8");
            document = saxReader.read(is);
        } catch (Exception e) {
            log.error("文件转Document文档异常：{}", e.getLocalizedMessage());
        }
        return document;
    }

    /**
     * 对象转Document文档
     */
    public static <T> Document toDocument(T t) throws Exception {
        ByteArrayOutputStream baos = null;
        try {
            JAXBContext ctx = JAXBContext.newInstance(t.getClass());
            baos = new ByteArrayOutputStream();
            Marshaller marshaller = ctx.createMarshaller();
            marshaller.marshal(t, baos);
            byte[] ba = baos.toByteArray();
            InputStream is = new ByteArrayInputStream(ba);
            baos.flush();
            return load(is);
        } catch (Exception e) {
            log.error("对象转Document文档异常：{}", e.getMessage());
        } finally {
            if (null != baos) {
                baos.close();
            }
        }
        return null;
    }

    /**
     * 解析XML并将其节点元素转成Map
     */
    public static final Map parseXmlToMap(String xml) {
        Map map = new HashMap();
        String strTitle = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
        if (xml.indexOf("<?xml") < 0) {
            xml = strTitle + xml;
        }
        Document document = toDocument(xml);
        // 获取根节点
        Element elNode = document.getRootElement();
        // 遍历节点属性值
        for (Iterator it = elNode.elementIterator(); it.hasNext(); ) {
            Element leaf = (Element) it.next();
            map.put(leaf.getName(), parseElement(leaf));
        }
        return map;
    }

    public static Map parseElement(Element e) {
        Map map = new HashMap();
        List list = e.elements();
        if (list.size() > 0) {
            List mapList = null;
            for (int i = 0; i < list.size(); i++) {
                Element iter = (Element) list.get(i);
                if (iter.elements().size() > 0) {
                    Map m = parseElement(iter);
                    if (null != map.get(iter.getName())) {
                        Object obj = map.get(iter.getName());
                        if (!"java.util.ArrayList".equals(obj.getClass().getName())) {
                            mapList = new ArrayList();
                            mapList.add(obj);
                            mapList.add(m);
                        } else if ("java.util.ArrayList".equals(obj.getClass().getName())) {
                            mapList = (List) obj;
                            mapList.add(m);
                        }
                        map.put(iter.getName(), mapList);
                    } else {
                        map.put(iter.getName(), m);
                    }
                } else {
                    if (null != map.get(iter.getName())) {
                        Object obj = map.get(iter.getName());
                        if (!"java.util.ArrayList".equals(obj.getClass().getName())) {
                            mapList = new ArrayList();
                            mapList.add(obj);
                            mapList.add(iter.getText());
                        } else if ("java.util.ArrayList".equals(obj.getClass().getName())) {
                            mapList = (List) obj;
                            mapList.add(iter.getText());
                        }
                        map.put(iter.getName(), mapList);
                    } else {
                        map.put(iter.getName(), iter.getText());
                    }
                }
            }
        } else {
            map.put(e.getName(), e.getText());
        }
        return map;
    }

    /**
     * 将Dto转换为符合XML标准规范格式的字符串(基于节点值形式)
     *
     * @param map           传入的Dto对象
     * @param pRootNodeName 根结点名
     */
    public static final String parseMapToXml(Map<String, String> map, String pRootNodeName) {
        Document document = DocumentHelper.createDocument();
        // 增加一个根元素节点
        document.addElement(pRootNodeName);
        Element root = document.getRootElement();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            Element leaf = root.addElement(entry.getKey());
            leaf.setText(entry.getValue());
        }

        String outXml = document.asXML();
        // 将XML的头声明信息截去
        // outXml = outXml.substring(39);
        return outXml;
    }
}
